﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Windows.Forms;
using System.Threading;

namespace MMOG
{
    public class CoreHandler
    {
        public TcpClient client;
        StreamWriter writer;
        StreamReader reader;
        Account account = null;

        public CoreHandler(TcpClient client)
        {
            this.client = client;
            writer = new StreamWriter(client.GetStream());
            reader = new StreamReader(client.GetStream());
        }

        public bool authenticate()
        {
            try
            {
                while (true)
                {
                    String s = reader.ReadLine();
                    if (s == null) return false;
                    Information info = new Information(s);
                    String username = info.getString("username");
                    String password = info.getString("password");
                    account = Database.authenticate(username, password);
                    if (account != null)
                    {
                        writer.WriteLine("Ok");
                        writer.Flush();
                        return true;
                    }
                    else
                    {
                        Server.addLog(client.Client.RemoteEndPoint.ToString() + ": Authentication failed!\n", MessageType.Report);
                        writer.WriteLine("Deny");
                        writer.Flush();
                        return false;
                    }
                }
            }
            catch (IOException)
            {
                return false;
            }
        }

        public static void sendChat(String username, String message)
        {
            Information info = new Information(Information.CHAT_MESSAGE);
            info.add("message", message);
            for (int i = 0; i < Server.handlerList.Count; i++)
            {
                if ((username == null) || (Server.handlerList[i].account.username.CompareTo(username) == 0))
                    lock (Server.handlerList[i].writer)
                    {
                        Server.handlerList[i].writer.WriteLine(info.ToString());
                        Server.handlerList[i].writer.Flush();
                    }
            }
        }

        public static void sendPopup(String username, String message)
        {
            Information info = new Information(Information.POPUP_MESSAGE);
            info.add("message", message);
            for (int i = 0; i < Server.handlerList.Count; i++)
            {
                lock (Server.handlerList[i].writer)
                {
                    Server.handlerList[i].writer.WriteLine(info.ToString());
                    Server.handlerList[i].writer.Flush();
                }
            }
        }

        public static void sendKick(String username, String message)
        {
            Information info = new Information(Information.KICK_MESSAGE);
            info.add("message", message);
            for (int i = 0; i < Server.handlerList.Count; i++)
            {
                if ((username == null) || (Server.handlerList[i].account.username.CompareTo(username) == 0))
                    lock (Server.handlerList[i].writer)
                    {
                        Server.handlerList[i].writer.WriteLine(info.ToString());
                        Server.handlerList[i].writer.Flush();
                    }
            }
        }

        public void checkOfflineMessage()
        {
            List<OfflineMessage> msg = Database.getOfflineMessage(account.username);
            for (int i = 0; i < msg.Count; i++)
            {
                Information info = new Information(Information.OFF_MESSAGE);
                info.add("from", msg[i].from);
                info.add("msg", msg[i].msg);
                writer.WriteLine(info.ToString());
                writer.Flush();
            }
        }

        public void sendRoomInfo()
        {
            lock (writer)
            {
                Information info = new Information(Information.RESET_ROOM);
                writer.WriteLine(info.ToString());
                for (int i = 0; i < Server.roomList.Count; i++)
                {
                    Information inf = new Information(Information.ROOM_UPDATE);
                    inf.add("gameid", Server.roomList[i].id.ToString());
                    inf.add("name", Server.roomList[i].name);
                    inf.add("nPlayer", Server.roomList[i].nPlayer.ToString());
                    inf.add("password", Server.roomList[i].password);
                    writer.WriteLine(inf.ToString());
                }
                writer.Flush();
            }
        }

        public static void createRoom(String message)
        {
            Information info = new Information(message);
            int id = Server.roomId;
            Server.roomId++;
            String name = info.getString("name");
            int nPlayer = info.getInt("nPlayer");
            String password = info.getString("password");
            RoomInfo roomInfo = new RoomInfo(id, name, password, nPlayer, 2, 0);
            Server.roomList.Add(roomInfo);
            Server.addLog("New room created ("+id+")", MessageType.System);
        }

        public bool processMessages()
        {
            try
            {
                String message = reader.ReadLine();
                if (message == null) return false;
                Information info = new Information(message);
                Server.addLog(info.ToString(), MessageType.Report);
                int type = info.getInt("id");
                switch (type)
                {
                    case Information.CHAT_MESSAGE:
                        sendChat(null, account.username + ": " + info.getString("message"));
                        break;
                    case Information.BUG_REPORT:
                        Database.addBugReport(account.username, info.getString("message"));
                        break;
                    case Information.REQUEST_ROOM_LIST:
                        sendRoomInfo();
                        break;
                    case Information.CREATE_ROOM:
                        createRoom(message);
                        break;

                }

                return true;
            }
            catch (IOException)
            {
                return false;
            }
        }

        public void sendAllList()
        {
            lock (writer)
            {
                for (int i = 0; i < Server.handlerList.Count; i++)
                {
                    Information info = new Information(Information.LIST_UPDATE);
                    info.add("type", "add");
                    info.add("name", Server.handlerList[i].account.username);
                    writer.WriteLine(info.ToString());
                }
                writer.Flush();
            }
        }

        public void updateList(String type)
        {
            if (account == null) return;
            Information info = new Information(Information.LIST_UPDATE);
            info.add("type", type);
            info.add("name", account.username);
            for (int i = 0; i < Server.handlerList.Count; i++)
            {
                lock (Server.handlerList[i].writer)
                {
                    Server.handlerList[i].writer.WriteLine(info.ToString());
                    Server.handlerList[i].writer.Flush();
                }
            }
            if (type.Equals("add"))
            {
                Server.userOnline++;
                Server.addList(account.username + "@" + client.Client.RemoteEndPoint.ToString());
            }
            else if (type.Equals("remove"))
            {
                Server.userOnline--;
                Server.removeList(account.username + "@" + client.Client.RemoteEndPoint.ToString());
            }
        }

        public void run()
        {
            try
            {
                if (authenticate())
                {
                    Server.addLog(account.username + " authenticated!", MessageType.Report);
                    Server.handlerList.Add(this);
                    sendAllList();
                    updateList("add");
                    while (!Server.exited)
                    {
                        Thread.Sleep(3);
                        Application.DoEvents();
                        if (!processMessages()) break;
                    }
                }
            }
            catch (IOException)
            {
                return;
            }
            finally
            {
                Server.addLog(client.Client.RemoteEndPoint.ToString() + " closed!", MessageType.Report);
                Server.handlerList.Remove(this);
                updateList("remove");
                reader.Close();
                writer.Close();
                client.Close();
            }
        }

    }
}
